// webpack是node开发出来，采用node的模块导出语法
const path = require('path');
const fs = require('fs');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //抽离css为单独文件
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); //压缩css文件
const TerserPlugin = require('terser-webpack-plugin'); //压缩js文件
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const pages = fs.readdirSync(path.relative(__dirname, 'src/pages'));
// 多页面入口对象
const entryObject = Object.create(null);
// 创建多页面的html页面
const createHtml = [];
pages
  .filter(p => !p.includes('.')) //过滤掉包含.的非文件夹的内容
  .forEach(page => {
    // pagePath pages下的文件
    const pagePath = path.join(__dirname, 'src/pages', page);
    if (fs.statSync(pagePath).isDirectory()) {
      //这里要使用同步方法获取stat，这样才能在循环 外部拿到完整的值。否则只能得到最初定义的值
      // contents： pages下的文件内部的内容
      const contents = fs.readdirSync(pagePath);
      // 遍历文件夹内部的所有文件
      contents.forEach(content => {
        // 判断content类型是文件，排除index文件夹
        const judgeContentFileType = fs.statSync(path.join(pagePath, content)).isFile();
        if (
          judgeContentFileType &&
          (content.includes('index') || content.includes('main')) // index 或者 main开头的文件
        ) {
          const basename = path.basename(pagePath); //获取文件夹的名称
          // 生成多入口entryObject对象
          entryObject[basename] = path.join(pagePath, content);
          // 创建多页面html的数组
          createHtml.push(
            new HtmlWebpackPlugin({
              template: 'src/assets/index.html', //设置模板路径
              title: basename, //配置标题名，可在html中通过htmlWebpackPlugin.options.title获取
              filename: `${basename}.html`, //设置打包后的文件名
              minify: {
                collapseWhitespace: true,
                collapseDoubleQuotes: true,
              },
              chunks: [basename],
              hash: true,
            }),
          );
        }
      });
    }
  });
// console.log(entryObject, createHtml);
/* const entryObject = pages.reduce((prev, page) => {
  let pageName = page.split(".")[0];
  let temp = {}
  temp[pageName] = path.resolve("./src/pages", page)
  return { ...prev, ...temp };
}, {}); */

module.exports = {
  mode: 'development',
  devServer: {
    // 本地开发启动本地服务器，内部使用express
    static: {
      directory: path.join(__dirname, 'dist'), // 启动文件的入口
    },
    client: {
      progress: true, // 显示进度条
    },
    port: 3000, // 端口号
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        pathRewrite: { '^/api': '/' },
      },
    },
    compress: true, //开启压缩
    hot: true, //热更新,会在应用程序运行过程中，替换、添加或删除 模块，而无需重新加载整个页面。
    liveReload: false, //监听到文件变化时 dev-server 将会重新加载或刷新页面，如果在测试填写表单是会清除掉数据
    open: false, // 自动打开页面
  },
  // devtool: "source-map",
  entry: entryObject,
  output: {
    filename: '[name].[chunkhash:8].js', //[name][hash]通过[]设置变量，:number设置变量的长度
    path: path.join(__dirname, 'dist'), // 路径地址必须是绝对路径
    // libraryTarget: 'commonjs2', //输出的代码符合CommonJS模块化规范，以供给其它模块导入使用。
  },
  resolve: {
    // modules: [path.resolve("node_modules")], // 解析第三方包
    // extensions: [".js", ".css", ".json"], // 依次查找后缀类型的文件
    // mainFileds: ["style", "main"], // 可以改变查询package.json的main入口顺序
    // mainFiles: [], // 入口文件名
    alias: {
      src: './src',
      assets: './src/assets',
      pages: './src/pages',
    },
  },
  module: {
    rules: [
      {
        test: /\.js(x?)$/,
        exclude: /node_modules/,
        use: [
          { loader: 'thread-loader', options: { workers: 3 } },
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true, // 启用缓存
              presets: ['@babel/preset-env', '@babel/preset-react'],
            },
          },
          {
            loader: 'comment-remove-loader',
          },
        ],
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          // 让 tsc 把 vue 文件当成一个 TypeScript 模块去处理，以解决 moudle not found 的问题，tsc 本身不会处理 .vue 结尾的文件
          appendTsSuffixTo: [/\.vue$/],
        },
      },
      {
        test: /\.vue$/,
        use: ['vue-loader'],
      },
      {
        // 用正则去匹配要用该 loader 转换的 CSS 文件
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
      },
      {
        // 用正则去匹配要用该 loader 转换的 LESS 文件
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        type: 'javascript/auto',
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024 * 10, //小于10k的用url-loader处理，超过的用file-loader处理
              esModule: false,
              name: 'assets/[name].[ext]',
            },
          },
        ],
        exclude: /node_modules/,
      },
      {
        test: require.resolve('jquery'),
        loader: 'expose-loader', // TOD使用该load可以把需要处理的文件按需加载，减少对其他模块的影响
        options: {
          exposes: ['$', 'jQuery'],
        },
      },
    ],
  },
  // 这些模块通过注册在运行环境中的全局变量访问，不用被重复打包进输出的代码里
  /* externals: {
    // 可以把外部插件通过cdn外部引入，加速处理，并且不参加打包处理。需要在html模板中引入对应的cdn文件
    $: "jquery",
  }, */
  optimization: {
    minimizer: [new CssMinimizerPlugin(), new TerserPlugin({ parallel: 4, exclude: /node_modules/ })],
    minimize: true, //开发模式下，仍然压缩代码处理
    splitChunks: {
      chunks: 'all',
      minSize: 10000, //生成 chunk 的最小体积
      maxSize: 1024 * 500, //使用maxSize，告诉webpack尝试将大于maxSize个字节的chunk分割成较小的部分。这些较小的部分在体积上要大于minSize
      minSizeReduction: 1000,
      minRemainingSize: 0,
      minChunks: 1, //拆分前必须共享模块的最小 chunks 数。超过该数值则抽离为单独chunk
      maxAsyncRequests: 30, //按需加载时的最大并行请求数
      maxInitialRequests: 30, //入口点的最大并行请求数
      enforceSizeThreshold: 1024 * 100, //强制执行拆分的体积阈值和其他限制
      cacheGroups: {
        // 组名称
        common: {
          // 抽离公用代码
          name: 'chunk-common',
          chunks: 'all',
          minChunks: 2,
          maxInitialRequests: 5,
          minSize: 0,
          priority: 0,
          enforce: true,
          reuseExistingChunk: true,
        },
        styles: {
          name: 'styles',
          test: /\.(s?css|less|sass)$/,
          chunks: 'all',
          enforce: true,
          priority: 10,
        },
        vendors: {
          // 抽离第三方模块公用代码
          name: 'chunk-vendors',
          test: /[\\/]node_modules[\\/]/,
          chunks: 'all',
          priority: 1,
          enforce: true,
          reuseExistingChunk: true,
        },
        default: false,
      },
    },
  },
  plugins: [
    /* new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, 'dist', 'manifest.json'),
    }), */
    /*  new webpack.ProvidePlugin({
      //ProvidePlugin全局引入插件，会给每个模块提供一个$,供模块直接调用
      $: "jquery",
    }), */
    // new BundleAnalyzerPlugin(),
    new webpack.DefinePlugin({
      DEV: JSON.stringify('development'),
      FLAG: 'true',
    }),
    new CleanWebpackPlugin(), //打包编译前，可以清理历史文件
    new MiniCssExtractPlugin(), //抽离独立的css文件
    new VueLoaderPlugin(), //
    ...createHtml,
  ],
};
